package com.laogao.lesson050.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多线程事务处理工具类
 * <b>description</b>：Java进阶、性能优化实战案例100讲，微信公众号:程序员恰恰，源码 & 文档 & 技术支持，请加个人微信号：it3306 <br>
 * 该工具类用于在多线程环境下执行多个数据库操作，并确保这些操作要么全部成功提交，要么全部回滚。
 * <b>注意</b>：
 * 1. 确保任务是幂等的，避免因重试导致数据不一致。
 * 2. 配置事务管理器时，建议使用独立事务（如 REQUIRES_NEW），以避免嵌套事务问题。
 * <b>author</b>：ready lao_gao
 */
@Slf4j
public class MoreThreadTransactionUtils {

    /**
     * 执行多线程事务处理
     *
     * @param platformTransactionManager Spring 的事务管理器，用于控制事务的提交和回滚
     * @param taskList                   一个可变数量的 Runnable 任务，每个任务代表一个数据库操作
     * @return 如果所有任务都成功完成，则返回 true；否则返回 false
     * @throws IllegalArgumentException 如果传入的任务列表为空或长度为 0，则抛出此异常
     */
    public static boolean execute(PlatformTransactionManager platformTransactionManager, Runnable... taskList) {
        if (taskList == null || taskList.length == 0) {
            throw new IllegalArgumentException("任务列表不能为空");
        }

        // 任务数量
        int taskSize = taskList.length;
        // 成功完成的任务计数器（线程安全）
        AtomicInteger successfulTaskCount = new AtomicInteger(0);

        // 存储每个任务的 Future 对象，用于后续获取任务结果
        List<Future<?>> taskFutureList = new ArrayList<>(taskSize);

        // 创建循环屏障，确保所有线程在完成任务后同步提交或回滚事务
        CyclicBarrier cyclicBarrier = new CyclicBarrier(taskSize);

        // 创建固定大小的线程池，线程池大小与任务数量一致，以避免死锁
        // 核心原因 ：CyclicBarrier 的工作机制要求所有线程必须到达屏障点才能继续执行。
        // 如果线程池的线程数量不足，部分任务可能无法被执行，导致其他线程永远等待，最终形成死锁。
        ExecutorService executorService = Executors.newFixedThreadPool(taskSize);
        try {
            // 提交任务到线程池
            for (int i = 1; i <= taskSize; i++) {
                final int taskIndex = i;
                Future<?> future = executorService.submit(() -> {
                    TransactionStatus transactionStatus = null;
                    try {
                        // 开启事务
                        transactionStatus = platformTransactionManager.getTransaction(new DefaultTransactionAttribute());
                        log.debug("任务 {} 开始执行", taskIndex);

                        // 执行任务
                        taskList[taskIndex - 1].run();

                        // 标记任务成功
                        successfulTaskCount.incrementAndGet();
                        log.debug("任务 {} 完成，等待提交事务", taskIndex);
                    } catch (Throwable e) {
                        // 捕获所有异常，记录错误日志
                        log.error("任务 {} 执行失败，原因：{}", taskIndex, e.getMessage(), e);
                    } finally {
                        // 等待其他线程到达屏障点
                        try {
                            log.debug("任务 {} 到达屏障点", taskIndex);
                            cyclicBarrier.await();
                        } catch (Exception e) {
                            log.error("任务 {} 在等待屏障点时发生异常，原因：{}", taskIndex, e.getMessage(), e);
                        }
                    }

                    // 根据任务成功数量决定提交或回滚事务
                    if (transactionStatus != null) {
                        if (successfulTaskCount.get() == taskSize) {
                            // 所有任务成功，提交事务
                            log.debug("任务 {} 提交事务", taskIndex);
                            platformTransactionManager.commit(transactionStatus);
                        } else {
                            // 有任务失败，回滚事务
                            log.debug("任务 {} 回滚事务", taskIndex);
                            platformTransactionManager.rollback(transactionStatus);
                        }
                    }
                });
                taskFutureList.add(future);
            }

            // 等待所有任务完成
            for (Future<?> future : taskFutureList) {
                try {
                    future.get();
                } catch (Exception e) {
                    log.error("获取任务结果时发生异常，原因：{}", e.getMessage(), e);
                }
            }
        } finally {
            // 关闭线程池，释放资源
            executorService.shutdown();
        }

        // 返回是否所有任务都成功完成
        return successfulTaskCount.get() == taskSize;
    }
}